//这是一个名为demo的模块，描述接口
module demo (
    input           clk,//定义输入信号clk（时钟），默认1位宽，输入都是wire型变量
    input           rst_n,//定义输入信号rst_n（复位），默认1位宽
    input   [3:0]   i_data,//4位宽输入信号
    input   [3:0]   q_data,//4位宽输入信号
    input           ready_in,//1位宽输入信号
    input   [1:0]   sel,//2位宽输入信号
    output  [4:0]   out_data,//5位宽输出信号，默认wire型
    output          ready_out     //1位宽输出信号，默认wire型
);
    //定义reg型变量，位宽4位
    reg [3:0] i_data_reg;
    reg [3:0] q_data_reg;
    reg [3:0] out_data_reg;

    reg [3:0] cnt;

    //计数器
    always @(posedge clk or negedge rst_n) begin//敏感列表，时钟上升沿或复位下降沿
        if(!rst_n)//复位信号为0（低电平复位）
            cnt<=4'b0;//cnt非阻塞赋值为0
        
        else if(cnt==4'd8)//cnt到达十进制8时清零
            cnt<=4'b0;
        
        else //未接收到复位信号且未达到8时加1
            cnt<=cnt+1'b1;
    end

    //reg in
    always @(posedge clk or negedge rst_n) begin//同上
        if(!rst_n)//低电平复位，赋初值0
            i_data_reg<=4'd0;
        else if(cnt==4'd4)//cnt为4，给i_data_reg赋3
            i_data_reg<=4'd3;
        else if(ready_in)//如果ready_in为1，把i_data的值给i_data_reg
            i_data_reg<=i_data;
    end
    always @(posedge clk or negedge rst_n) begin//同上
        if(!rst_n)//低电平复位，赋初值0
            q_data_reg<=4'd0;
        else if(cnt==4'd4)//cnt为4，给q_data_reg赋3
            q_data_reg<=4'd3;
        else if(ready_in)//如果ready_in为1，把q_data的值给q_data_reg
            q_data_reg<=q_data;
    end  

//-------------------------------------写法1------------------------------------------//
/*
    //MUX
    always @(*) begin
        case (sel)
            2'b00:  out_data_reg = i_data_reg;
            2'b01:  out_data_reg = i_data_reg * q_data_reg;
            2'b10:  out_data_reg = i_data_reg & q_data_reg;
            2'b11:  out_data_reg = i_data_reg && q_data_reg;
            default:;
        endcase
    end

    assign out_data = out_data_reg;
    assign ready_out = ready_in;
*/

//-------------------------------------写法2------------------------------------------//

    //MUX
    assign out_data = (sel==2'b00) ?  i_data_reg : 
                      (sel==2'b01) ? (i_data_reg * q_data_reg) :
                      (sel==2'b10) ? (i_data_reg & q_data_reg) :
                                     (i_data_reg && q_data_reg);
    //这是一个用三目运算符实现的多路选择器，其功能和上面用case实现的完全一致。
    //三目运算符优先级低于括号和单目运算符，从后往前判断。
    //通过一个举例说明它是如何工作的。如果sel==2'b10，则第三个三目的判断位置为True，
    //第三个三目运算符输出i_data_reg & q_data_reg,此时化简后的表达式为：
    //assign out_data = (sel==2'b00) ?  i_data_reg : 
    //                  (sel==2'b01) ? (i_data_reg * q_data_reg) :  (i_data_reg & q_data_reg)
    //由于同一时刻sel只能有一个确定值，所以前两个三目运算符逻辑判断都为False，均选择：后的值作为输出，化简为：
    //assign out_data = (sel==2'b00) ?  i_data_reg : (i_data_reg & q_data_reg)
    //即assign out_data = (i_data_reg & q_data_reg)
    //可以看到，当sel=2'b10,out_data=i_data_reg & q_data_reg,和上面用case的实现相同，同理其他几种情况也可以根据这个原理得到与上面一样的结果
    //其中，&&是逻辑与，&是按位与，按位与得到一个与原来相同位宽，每一位取两变量对应位的与的新数值，
    //而逻辑与得到1或0（不考虑高阻态和不定态），只有两个变量都不为0（两个变量中任意一位不为0），则输出0，只要有一个变量所有位都是0就得到0
    assign ready_out = ready_in;//阻塞赋值，因为这是给wire型变量赋值

endmodule